<style lang="less" scoped>
  @import (reference) "../../assets/styles/common.less";
  .line-field {
    legend {
      font-weight: 800;
    }
  }

  .keyframes (enter-bounce, {
      0% {
        .transform(scale(0));
        background-color: rgba(250, 220, 174, 0.87);
      }
      50% {
        .transform(scale(1.2));
      }
      100% {
        .transform(scale(1));
        background-color: inherit;
      }
  });

  /* 可以设置不同的进入和离开动画 */
  /* 设置持续时间和动画函数 */
  .list-complete {
    &-enter {
      &-active {
        .animation(enter-bounce, 1.2s, ease, 0s, 1, normal, forwards);
      }
    }
  }

  .form-container {
    .link-wrapper {
      position: fixed;
      top: 150px;
      right: 45px;
      width: 125px;
    }

    .ivu-divider-dashed {
      border-color: #ccc;
      padding-top: 20px;
    }
  }

  #edit-modal .ivu-modal-body .form-container .link-wrapper {
    top: 165px;
    right: 62px;
  }
</style>

<template>
  <div class="form-container">
    <div class="link-wrapper">
      <Anchor
        :affix="false"
        :offset-top="200"
        :scroll-offset="-110"
        :container="scrollContainer"
        show-ink>
        <AnchorLink href="#course_info" :scroll-offset="110" title="课程基本信息"/>
        <AnchorLink href="#exp_info" title="实验基本信息" v-if="applyForm.teacher_code && applyForm.course_code">
          <AnchorLink
            v-for="(expBaseInfoItem, expBaseInfoIndex) in applyForm.expBaseInfoItems"
            :key="expBaseInfoItem.guid"
            :href="`#exp_item_${expBaseInfoIndex + 1}`"
            :title="`实验${expBaseInfoIndex + 1}`" />
        </AnchorLink>
        <AnchorLink href="#actions" title="提交 / 重置" v-if="applyForm.teacher_code && applyForm.course_code" />
      </Anchor>
    </div>
    <div class="form-wrapper">
      <Form
        ref="applyForm"
        :model="applyForm"
        :rules="ruleValidate"
        :label-position="labelPosition"
        :label-width="labelWidth"
        style="width: calc(100% - 150px)">
        <fieldset class="line-field" id="course_info">
          <legend>课程基本信息</legend>
          <FormItem label="所属学院" prop="institute">
            <Select
                v-model="applyForm.institute"
                filterable
                :disabled="!userAccess.some(item => { return ['ROLE_SCHOOL_ADMIN', 'ROLE_ROOT'].indexOf(item) > -1 }) || isModified"
                v-if="userAccess.some(item => { return ['ROLE_SCHOOL_ADMIN', 'ROLE_ROOT'].indexOf(item) > -1 }) && !isModified"
                :enabledPreventOverflow="enabledPreventOverflow"
                :not-found-text="instituteLoading ? '查询学院中，请稍等...' : '无可选学院'"
                @on-change="onSelectInstitute"
                placeholder="请选择教师所属学院">
                <Option v-for="(option, index) in instituteOptions" :value="option" :key="index">{{option}}</Option>
            </Select>
            <Input v-else v-model="applyForm.institute" readonly placeholder="教师所属学院" />
          </FormItem>
          <FormItem label="教师姓名" prop="teacher_code" v-if="applyForm.institute">
            <Select
                v-model="applyForm.teacher_code"
                filterable
                :disabled="!userAccess.some(item => { return ['ROLE_ROOT', 'ROLE_SCHOOL_ADMIN', 'ROLE_INSTITUTE_ADMIN'].indexOf(item) > -1 }) || isModified"
                v-if="userAccess.some(item => { return ['ROLE_SCHOOL_ADMIN', 'ROLE_ROOT', 'ROLE_INSTITUTE_ADMIN'].indexOf(item) > -1 }) && !isModified"
                :enabledPreventOverflow="enabledPreventOverflow"
                :not-found-text="teaLoading ? '查询教师中，请稍等...' : '无可选教师'"
                :label-in-value="true"
                @on-change="onSelectTeacher"
                placeholder="请先选择教师">
                <Option v-for="(option, index) in teacherOptions" :value="option.code" :key="index">{{option.name}}</Option>
            </Select>
            <Input v-else v-model="applyForm.teacher_name" readonly placeholder="教师姓名" />
          </FormItem>
          <FormItem label="课程" prop="course_code" v-if="applyForm.institute && applyForm.teacher_code">
            <Select
                v-model="applyForm.course_code"
                filterable
                clearable
                :disabled="isModified"
                v-if="!isModified"
                :enabledPreventOverflow="enabledPreventOverflow"
                :not-found-text="courseLoading ? '查询课程中，请稍等...' : '该教师无可选课程'"
                @on-change="onSelectCourse"
                placeholder="请先选择课程">
              <Option v-for="(option, index) in courseOptions" :value="option.code" :key="index">{{ option.name + '(' + option.code + ')' }}</Option>
            </Select>
            <Input v-else v-model="courseName" readonly placeholder="课程" />
          </FormItem>
          <FormItem label="实验教材" prop="textbook" v-if="applyForm.teacher_code && applyForm.course_code">
            <Input type="textarea" v-model="applyForm.textbook" clearable placeholder="实验指导书名称，编(写)者，出版社，出版日期" :autosize="{minRows: 2, maxRows: 6}"></Input>
          </FormItem>
          <FormItem label="班级信息" prop="classes" v-if="applyForm.teacher_code && applyForm.course_code">
            <Row :gutter="20" type="flex" justify="space-between" v-if="classesList.length > 0">
              <div style="width: 100%; border-bottom: 1px solid #e9e9e9;padding-bottom:6px;margin-bottom:6px;">
                <Checkbox
                    :indeterminate="classesIndeterminate"
                    :value="classesCheckAll"
                    @click.prevent.native="handleCheckAllClasses">全选</Checkbox>
              </div>
              <CheckboxGroup v-model="applyForm.classes" style="width: 100%">
                <Col :xs="22" :sm="24" :md="11" v-for="(item, index) in classesList" :key="index">
                  <Checkbox :label="JSON.stringify(item)" style="margin-right: 20px">
                    {{ item.grade + item.major + item.sclass + "班" }}
                  </Checkbox>
                </Col>
              </CheckboxGroup>
            </Row>
            <Alert v-else-if="classesLoading" show-icon type="info">加载班级中，请稍等...</Alert>
            <Alert v-else show-icon type="error">该课程暂无班级，请选择其他课程</Alert>
          </FormItem>
          <!-- <FormItem label="人数" prop="stu_num" v-if="applyForm.teacher_code && applyForm.course_code">
              <InputNumber :min="1" v-model="applyForm.stu_num" placeholder="总人数" style="width: 220px"></InputNumber>
          </FormItem> -->
        </fieldset>
        <div v-if="!historyLoading">
          <transition-group name="list-complete" tag="div" id="exp_info" v-if="applyForm.teacher_code && applyForm.course_code"
                            @leave="leave">
            <fieldset
                class="line-field list-complete-item"
                v-for="(expBaseInfoItem, expBaseInfoIndex) in applyForm.expBaseInfoItems"
                ref="baseInfoRef"
                :key="expBaseInfoItem.guid"
                :id="`exp_item_${expBaseInfoIndex + 1}`">
              <legend>实验{{ expBaseInfoIndex + 1 }} 基本信息</legend>
              <FormItem label="基本信息" class="ivu-form-item-required">
                <Row :gutter="20" type="flex" justify="space-around" style="margin-bottom: 6px">
                  <Col span="2" class="pl-15">编号：</Col>
                  <Col span="5">
                    <FormItem>
                      <Input disabled placeholder="实验编号" :value="expBaseInfoIndex + 1"></Input>
                    </FormItem>
                  </Col>
                  <Col span="2" class="pl-15">类型：</Col>
                  <Col span="6">
                    <FormItem :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.type'" :rules="ruleValidate.type">
                      <Select :enabledPreventOverflow="enabledPreventOverflow" clearable filterable v-model="expBaseInfoItem.type" placeholder="实验类型">
                        <Option value="验证性">验证性</Option>
                        <Option value="演示性">演示性</Option>
                        <Option value="练习性">练习性</Option>
                        <Option value="创新性">创新性</Option>
                        <Option value="设计性">设计性</Option>
                        <Option value="综合性">综合性</Option>
                        <Option value="其他">其他</Option>
                      </Select>
                    </FormItem>
                  </Col>
                  <Col span="2" class="pl-15">学时：</Col>
                  <Col span="6">
                    <FormItem :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.learntime'" :rules="ruleValidate.learntime">
                      <InputNumber ref="learntime" :min="1" v-model="expBaseInfoItem.learntime" style="width: 100%"
                                  placeholder="计划学时"></InputNumber>
                    </FormItem>
                  </Col>
                </Row>
              </FormItem>
              <FormItem label="项目名称" :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.title'" :rules="ruleValidate.title">
                  <Input v-model="expBaseInfoItem.title" clearable placeholder="请输入实验项目名称"></Input>
              </FormItem>
              <FormItem label="耗材需求" :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.resources'"
                        :rules="ruleValidate.resources">
                  <Input type="textarea" v-model="expBaseInfoItem.resources" clearable @on-blur="blur_need('resources', expBaseInfoIndex)" placeholder="本次实验的耗材需求"></Input>
              </FormItem>
              <FormItem label="系统需求" :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.system'" :rules="ruleValidate.system">
                  <Input type="textarea" v-model="expBaseInfoItem.system" clearable @on-blur="blur_need('system', expBaseInfoIndex)" placeholder="本次实验的系统需求"></Input>
              </FormItem>
              <FormItem label="软件需求" :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.software'"
                        :rules="ruleValidate.software">
                  <Input type="textarea" v-model="expBaseInfoItem.software" clearable @on-blur="blur_need('software', expBaseInfoIndex)" placeholder="本次实验的软件需求"></Input>
              </FormItem>
              <FormItem
                  label="时间及实验室"
                  v-for="(timeItem, expTimeIndex) in expBaseInfoItem.expTimeItems"
                  :key="timeItem.guid"
                  class="ivu-form-item-required ivu-divider-dashed">
                <Row :gutter="20" type="flex" justify="space-between">
                  <Col span="2" class="pl-15">周次：</Col>
                  <Col span="10">
                    <FormItem
                        :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.expTimeItems.' + expTimeIndex + '.sweek'"
                        :rules="ruleValidate.sweek">
                      <Select :enabledPreventOverflow="enabledPreventOverflow" v-model="timeItem.sweek" placeholder="第几周" filterable clearable @on-change="onChangeTime(expBaseInfoIndex, expTimeIndex, 'sweek')">
                        <Option v-for="(n, index) in 21" :value="n" :key="index">{{ n }}</Option>
                      </Select>
                    </FormItem>
                  </Col>
                  <Col span="2" class="pl-15">星期：</Col>
                  <Col span="10">
                    <FormItem
                        :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.expTimeItems.' + expTimeIndex + '.sdate'"
                        :rules="ruleValidate.sdate">
                      <Select :enabledPreventOverflow="enabledPreventOverflow" v-model="timeItem.sdate" placeholder="星期几" filterable clearable @on-change="onChangeTime(expBaseInfoIndex, expTimeIndex, 'sdate')">
                        <Option value=1>一</Option>
                        <Option value=2>二</Option>
                        <Option value=3>三</Option>
                        <Option value=4>四</Option>
                        <Option value=5>五</Option>
                        <Option value=6>六</Option>
                        <Option value=7>天</Option>
                      </Select>
                    </FormItem>
                  </Col>
                </Row>
                <br>
                <Row :gutter="20" type="flex" justify="space-between">
                  <Col span="2" class="pl-15">节次：</Col>
                  <Col span="10">
                    <FormItem
                        :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.expTimeItems.' + expTimeIndex + '.section'"
                        :rules="ruleValidate.section">
                      <!-- <Select :enabledPreventOverflow="enabledPreventOverflow" v-model="timeItem.section" multiple placeholder="第几节" filterable v-if="isFilledForming && !isFilledFormByData">
                        <Option v-for="n in 11" :value="n" :key="n">{{ n }}</Option>
                      </Select> -->
                      <Select :enabledPreventOverflow="enabledPreventOverflow" v-model="timeItem.section" multiple placeholder="第几节" filterable @on-change="onChangeTime(expBaseInfoIndex, expTimeIndex, 'section')">
                        <Option v-for="n in 11" :value="n" :key="n">{{ n }}</Option>
                      </Select>
                    </FormItem>
                  </Col>
                  <Col span="2" class="pl-15 pr-0">学院：</Col>
                  <Col span="10" >
                    <FormItem :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.expTimeItems.' + expTimeIndex + '.institute'"
                            :rules="ruleValidate.institute">
                      <Select v-model="timeItem.institute"
                              :enabledPreventOverflow="enabledPreventOverflow"
                              placeholder="请选择实验室所属学院"
                              filterable
                              :not-found-text="instituteLoading ? '查询学院中，请稍等...' : '无可选学院'"
                              @on-change="onChangeTime(expBaseInfoIndex, expTimeIndex, 'institute')">
                        <Option v-for="(option, index) in instituteOptions" :value="option" :key="index">{{ option }}</Option>
                      </Select>
                    </FormItem>
                  </Col>
                </Row>
                <br>
                <Row :gutter="20" type="flex" justify="space-between">
                  <Col span="2" class="pl-15 pr-0">实验室：</Col>
                  <Col span="12" style="width: 65%; padding-left: 5px; padding-right: 13px;">
                    <FormItem
                        :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.expTimeItems.' + expTimeIndex + '.classroom'"
                        :rules="ruleValidate.classroom">
                      <Select v-model="timeItem.classroom"
                              :enabledPreventOverflow="enabledPreventOverflow"
                              :disabled="!(timeItem.institute && timeItem.sweek && timeItem.sdate && timeItem.section.length > 0)"
                              :placeholder="(timeItem.institute && timeItem.sweek && timeItem.sdate && timeItem.section.length > 0) ? '请选择实验室' : '请先选择学院和实验时间'"
                              filterable
                              clearable
                              multiple
                              :loading="timeItem.labLoading"
                              loading-text="查询实验室中，请稍等">
                        <Option
                          v-for="item in applyForm.expBaseInfoItems[expBaseInfoIndex].expTimeItems[expTimeIndex].laboratoryList"
                          :label="item.code"
                          :value="item.code"
                          :key="item.code"
                          :disabled="!('ACTIVATING'===item.status)">
                              <span>{{ item.code }}</span>
                              <span style="float:right;color:#ccc;margin-right: 15px;">{{ item.name + ' (' + item.capacity + '人)' }}</span>
                        </Option>
                      </Select>
                    </FormItem>
                  </Col>
                  <Col span="1"></Col>
                  <Col span="5" class="text-right">
                    <Poptip
                        confirm
                        title="确认删除该实验时间吗？"
                        @on-ok="remove_time(expBaseInfoItem, timeItem, expTimeIndex)"
                        v-if="!(expTimeIndex === 0 && expBaseInfoItem.expTimeItems.length === 1)"
                        :options="popperOpts"
                        class="text-left">
                      <Tooltip content="删除该实验时间">
                        <Button type="warning" shape="circle" icon="md-trash"></Button>
                      </Tooltip>
                    </Poptip>
                    <Tooltip content="新增实验时间"
                            v-if="expTimeIndex + 1 === expBaseInfoItem.expTimeItems.length"
                            style="margin-left: 1.5em">
                      <Button type="info" shape="circle" icon="md-add"
                              @click="add_time(expBaseInfoItem.expTimeItems)"></Button>
                    </Tooltip>
                  </Col>
                </Row>
              </FormItem>
              <div class="text-right position-relative ivu-divider-dashed">
                  <Poptip
                      confirm
                      :title="'确认删除实验' + (expBaseInfoIndex + 1) + '吗?'"
                      @on-ok="remove_exp_info(expBaseInfoItem, expBaseInfoIndex)"
                      v-if="!(expBaseInfoIndex === 0 && applyForm.expBaseInfoItems.length === 1)"
                      class="text-left"
                      :options="popperOpts">
                      <Button type="warning" icon="ios-close-circle-outline">删除实验{{ expBaseInfoIndex + 1 }}</Button>
                  </Poptip>
                  <Button type="primary" icon="md-add"
                          @click="add_exp_info"
                          v-if="expBaseInfoIndex + 1 === applyForm.expBaseInfoItems.length"
                          style="margin-left: 1.5em">
                    增加到实验{{ expBaseInfoIndex + 2 }}
                  </Button>
              </div>
            </fieldset>
          </transition-group>
        </div>
      </Form>
    </div>
    <div class="modal-container">
      <Modal v-model="modal.occupy.show" width="75" @on-ok="modal.occupy.show = false" footer-hide>
        <p slot="header" class="text-center" style="color:#f60;">
          <Icon type="ios-information-circle"></Icon>
          <span>{{ modal.occupy.title }}</span>
        </p>
        <div>
          <Table height="400" border size="small" :columns="occupyColumns" :data="occupyData.table" class="small-table"></Table>
        </div>
      </Modal>
      <Modal v-model="modal.detail.show" footer-hide width="90%" class="mb-50-modal">
        <p slot="header" class="text-center" style="color: #276f86;">{{ modal.detail.title }}</p>
        <applied-form-detail-table v-if="modal.detail.show" :code="modal.detail.code" :title="modal.detail.title"/>
      </Modal>
    </div>
  </div>
</template>
<script>
import Velocity from 'velocity-animate'
import { getUserByCode, getInstituteList, getTeacherList, getCourseByTeacherCode, getLabByTimes, getClassesByCourse, submitApply, editApply } from '@/api/apply-form'
import { generateGuid } from '@/libs/tools'
import { mapActions } from 'vuex'
import AppliedFormDetailTable from '_c/applied-form-detail-table/applied-form-detail-table'
export default {
  name: 'ApplyForm',
  components: {
    'applied-form-detail-table': AppliedFormDetailTable
  },
  data () {
    const validateLearntime = (rule, value, callback) => {
      let expIndex = rule.field.split('.')[1]
      let timeItems = this.applyForm.expBaseInfoItems[expIndex].expTimeItems
      let allLearntime = 0
      timeItems.forEach(item => {
        allLearntime = allLearntime + (item.section.length || 0)
      })
      if (allLearntime < value) {
        callback(new Error('计划学时小于实际学时(一节次一学时)，请调整节次或计划学时'))
      } else {
        callback()
      }
    }
    return {
      scrollContainer: '',
      userAccess: [],
      teacherOptions: [],
      courseOptions: [],
      classesList: [],
      instituteOptions: [],
      teaLoading: true,
      courseLoading: false,
      classesLoading: false,
      submitLoading: false,
      instituteLoading: true,
      // 全选班级的 indeterminate 状态，只负责样式控制
      classesIndeterminate: false,
      // 班级是否全选
      classesCheckAll: false,
      // 是否已经填充完通过code获取详细信息的数据
      isFilledFormByData: false,
      // 是否处于填充表单的状态
      isFilledForming: false,
      // 修改申请表时的course_name
      courseName: '',
      // 是否在加载历史数据，避免动画效果一次过全部出来
      historyLoading: false,
      timer: '',
      /* 利用MutationObserver实现监听元素class的变化 */
      observers: null,
      applyForm: {
        exp_type: 'COURSE',
        institute: null,
        teacher_code: null,
        teacher_name: null,
        course_code: null,
        textbook: null,
        classes: [],
        // stu_num: null,
        expBaseInfoItems: [
          {
            guid: generateGuid(),
            sid: 1,
            type: null,
            title: null,
            learntime: null,
            resources: null,
            system: null,
            software: null,
            expTimeItems: [
              {
                guid: generateGuid(),
                institute: null,
                sweek: null,
                sdate: null,
                section: [],
                classroom: [],
                laboratoryList: [],
                labLoading: false
              }
            ]
          }
        ]
      },
      ruleValidate: {
        institute: [
          {required: true, message: '学院不能为空', trigger: 'change'}
        ],
        teacher_code: [
          {required: true, message: '教师不能为空', trigger: 'change'}
        ],
        course_code: [
          {required: true, message: '课程名字不能为空', trigger: 'change'}
        ],
        textbook: [
          {required: true, message: '实验教材详细情况不能为空', trigger: 'blur'}
        ],
        classroom: [
          {required: true, type: 'array', message: '实验室不能为空', trigger: 'change'}
        ],
        classes: [
          {required: true, type: 'array', min: 1, message: '至少选择一个班级', trigger: 'change'}
        ],
        stu_num: [
          {required: true, type: 'number', message: '人数不能为空', trigger: 'change'},
          {required: true, type: 'number', message: '人数不能为空', trigger: 'blur'}
        ],
        type: [
          {required: true, message: '实验类型不能为空', trigger: 'change'}
        ],
        title: [
          {required: true, message: '项目名称不能为空', trigger: 'blur'}
        ],
        sweek: [
          {required: true, type: 'number', message: '周次不能为空', trigger: 'change'}
        ],
        sdate: [
          {required: true, message: '星期不能为空', trigger: 'change'}
        ],
        section: [
          {required: true, type: 'array', message: '节次不能为空', trigger: 'change'}
        ],
        date: [
          {required: true, type: 'array', message: '实训时间不能为空', trigger: 'change'}
        ],
        learntime: [
          {validator: validateLearntime, type: 'change'},
          {validator: validateLearntime, type: 'blur'},
          {required: true, type: 'number', message: '学时不能为空', trigger: 'change'},
          {required: true, type: 'number', message: '学时不能为空', trigger: 'blur'}
        ],
        resources: [
          {required: true, message: '耗材需求不能为空', trigger: 'blur'}
        ],
        system: [
          {required: true, message: '系统需求不能为空', trigger: 'blur'}
        ],
        software: [
          {required: true, message: '软件需求不能为空', trigger: 'blur'}
        ]
      },
      labelPosition: 'left',
      labelWidth: 100,
      // Select选择器的下拉列表是否吸附，默认为true，吸附
      enabledPreventOverflow: false,
      popperOpts: {
        modifiers: {
          preventOverflow: {
            // 边界元素: scrollParent, window, viewport or any DOM element. 默认iview默认window
            boundariesElement: 'scrollParent'
          }
        }
      },
      occupyColumns: [
        {
          title: '实验编号',
          key: 'expIndex',
          width: 60,
          align: 'center'
        },
        {
          title: '周次',
          key: 'weekNumber',
          sortable: true,
          width: 60,
          align: 'center'
        },
        {
          title: '星期',
          key: 'week',
          sortable: true,
          width: 60,
          align: 'center'
        },
        {
          title: '节次',
          key: 'section',
          sortable: true,
          width: 60,
          align: 'center'
        },
        {
          title: '实验室',
          key: 'code',
          minwidth: 150,
          align: 'center'
        },
        {
          title: '已申请的申请表相关信息',
          align: 'center',
          children: [
            {
              title: '教师姓名',
              key: 'teacherName',
              align: 'center',
              width: 60
            },
            {
              title: '课程名称',
              key: 'courseName',
              align: 'center'
            },
            {
              title: '实验编号',
              key: 'experimentNumber',
              align: 'center',
              width: 60
            },
            {
              title: '实验名称',
              key: 'experimentName',
              align: 'center',
              minWidth: 120
            },
            {
              title: '操作',
              align: 'center',
              key: 'action',
              width: 80,
              render: (h, params) => {
                return h('div', [
                  h('Button', {
                    props: {
                      type: 'primary',
                      size: 'small'
                    },
                    on: {
                      click: () => {
                        this.openDetail(params)
                      }
                    }
                  }, '查看详情')
                ])
              }
            }
          ]
        }
      ],
      occupyData: {
        table: []
      },
      modal: {
        occupy: {
          show: false,
          title: '抱歉，提交失败，实验室使用时间冲突'
        },
        detail: {
          show: false,
          title: '',
          code: ''
        }
      }
    }
  },
  props: {
    interactiveData: {
      type: Object
    },
    pdfData: {
      type: Object
    },
    isModified: {
      type: Boolean,
      default: false
    }
  },
  created: function () {
    if (this.isModified) {
      this.showSpinWithTip('加载表单数据中，请稍等...')
    } else {
      // 当有localstorage且其课程代码course_code不为空时才显示加载历史记录
      if (localStorage.getItem('applyForm') && JSON.parse(localStorage.getItem('applyForm')).course_code) {
        this.historyLoading = true
        this.showSpinWithTip('加载历史数据中，请稍等...')
      }
      if (localStorage.getItem('courseOptions')) {
        this.courseOptions = JSON.parse(localStorage.getItem('courseOptions'))
      }
      if (localStorage.getItem('classesList')) {
        this.classesList = JSON.parse(localStorage.getItem('classesList'))
      }
    }
    // 获取当前登录的用户信息
    this.getUserInfo().then(response => {
      let res = response.data
      if (res.code === 1) {
        let code = this.$store.state.user.userCode // 教师工号
        let name = this.$store.state.user.userName // 教师姓名
        let access = this.userAccess = this.$store.state.user.access // 教师权限
        let institute = this.$store.state.user.department || '' // 教师权限
        if (access.some(item => { return ['ROLE_ROOT', 'ROLE_SCHOOL_ADMIN'].indexOf(item) > -1 })) {
          getInstituteList().then(response => {
            let res = response.data
            if (res.code && res.data.length > 0) {
              this.instituteOptions = res.data
              this.instituteLoading = false
              if (!this.isModified) {
                if (!(localStorage.getItem('applyForm') && JSON.parse(localStorage.getItem('applyForm')).course_code)) {
                  this.applyForm.institute = this.applyForm.expBaseInfoItems[0].expTimeItems[0].institute = this.instituteOptions.indexOf(institute) > -1 ? institute : null
                }
              }
            } else {
              this.$Spin.hide()
              this.$Notice.error({
                title: '发生错误',
                desc: res.info
              })
            }
          }).catch(error => {
            console.log(error)
            this.$Spin.hide()
            this.instituteLoading = false
            this.$Notice.error({
              title: '发生错误',
              desc: '抱歉，获取学院列表失败，请刷新后重试。'
            })
          })
        } else {
          this.instituteOptions = [institute]
        }
        if (access.some(item => { return ['ROLE_ROOT', 'ROLE_SCHOOL_ADMIN', 'ROLE_INSTITUTE_ADMIN'].indexOf(item) > -1 })) {
          // 如果是管理员，可获取教师列表
          this.teaLoading = true
          // 获取教师列表
          getTeacherList(institute).then(response => {
            let res = response.data
            if (res.code) {
              this.teacherOptions = res.data.length > 0 ? res.data : []
              if (res.data.length > 0) {
                this.$nextTick(() => {
                  if (!this.isModified) {
                    if (localStorage.getItem('applyForm') && JSON.parse(localStorage.getItem('applyForm')).course_code) {
                      // 当有localstorage及其课程代码course_code时才赋值旧数据
                      this.applyForm = JSON.parse(localStorage.getItem('applyForm'))
                      this.historyLoading = false
                    } else {
                      this.historyLoading = false
                      this.applyForm.institute = this.applyForm.expBaseInfoItems[0].expTimeItems[0].institute = this.instituteOptions.indexOf(institute) > -1 ? institute : null
                      this.applyForm.teacher_code = code
                      this.applyForm.teacher_name = name
                      this.onSelectTeacher({
                        'label': name,
                        'value': code
                      })
                    }
                  }
                })
              } else {
                this.$Notice.error({
                  title: '提示',
                  desc: '抱歉，暂无教师。'
                })
              }
            } else {
              this.$Notice.error({
                title: '获取教师列表失败',
                desc: res.info
              })
            }
            this.teaLoading = false
            if ((this.isModified && this.isFilledFormByData) || !this.isModified) {
              this.$nextTick(() => {
                setTimeout(() => {
                  this.historyLoading = false
                  this.$emit('hide-spin')
                }, 1000)
              })
            }
          }).catch(error => {
            console.log(error.stack)
            this.teaLoading = false
            this.$Notice.error({
              title: '提示',
              desc: '抱歉，暂无教师。'
            })
            if ((this.isModified && this.isFilledFormByData) || !this.isModified) {
              this.$nextTick(() => {
                this.$emit('hide-spin')
              })
            }
          })
        } else {
          // 非管理员时，不用获取教师列表，只显示且选择当前登录教师即可
          this.teacherOptions.push({
            code: code,
            name: name
          })
          if ((this.isModified && this.isFilledFormByData) || !this.isModified) {
            this.$nextTick(() => {
              this.$emit('hide-spin')
            })
          }
          if (localStorage.getItem('applyForm') && JSON.parse(localStorage.getItem('applyForm')).teacher_code === code) {
            // 如果localstorage的旧数据不是当前登录教师的，则不赋值
            if (!this.isModified) {
              this.applyForm = JSON.parse(localStorage.getItem('applyForm'))
            }
          } else {
            this.applyForm.institute = this.applyForm.expBaseInfoItems[0].expTimeItems[0].institute = institute
            this.applyForm.teacher_code = code
            this.applyForm.teacher_name = name
            this.onSelectTeacher({
              'label': name,
              'value': code
            })
          }
          this.$Spin.hide()
        }
      } else {
        this.$Spin.hide()
        this.$Notice.error({
          title: '获取信息失败',
          desc: '获取用户信息失败！' + res.info
        })
      }
    }).catch(error => {
      console.log(error)
      this.$Spin.hide()
      this.$Notice.error({
        title: '获取信息失败',
        desc: '获取用户信息失败！'
      })
    })
  },
  mounted: function () {
    // 全局配置Notice组件的属性
    this.$Notice.config({
      top: window.innerHeight / 3,
      duration: 4
    })
    this.scrollContainer = this.isModified ? document.querySelector('#edit-modal .ivu-modal-wrap') : document.querySelector('.content-wrapper.ivu-layout-content')
    this.startMutationObserver()
  },
  beforeDestroy () {
    this.$Notice.destroy()
    /* 利用MutationObserver实现监听元素class的变化 */
    if (this.observer) {
      this.observer.disconnect()
      this.observer.takeRecords()
      this.observer = null
    }
  },
  methods: {
    ...mapActions([
      'getUserInfo'
    ]),
    async getTeacherOptions (institute) {
      try {
        let response = await getTeacherList(institute)
        let res = response.data
        if (res.code) {
          return res.data.length > 0 ? res.data : []
        } else {
          this.$Notice.error({
            title: '获取教师列表失败',
            desc: res.info
          })
          return []
        }
      } catch (error) {
        console.log(error)
        return []
      }
    },
    // 选择学院的回调
    async onSelectInstitute (value) {
      if (value && !this.isModified) {
        this.teacherOptions = await this.getTeacherOptions(value)
        this.applyForm = {
          exp_type: 'COURSE',
          institute: value,
          teacher_code: '',
          teacher_name: '',
          course_code: null,
          textbook: null,
          classes: [],
          // stu_num: null,
          expBaseInfoItems: [
            {
              guid: generateGuid(),
              sid: 1,
              type: null,
              title: null,
              learntime: null,
              resources: null,
              system: null,
              software: null,
              expTimeItems: [
                {
                  guid: generateGuid(),
                  institute: value,
                  sweek: null,
                  sdate: null,
                  section: [],
                  classroom: [],
                  laboratoryList: [],
                  labLoading: false
                }
              ]
            }
          ]
        }
      }
    },
    // 选择教师后的回调，根据 教师代码 获取其课程
    onSelectTeacher (value) {
      let institute = this.applyForm.institute
      if (value && !this.isModified) {
        let teacher = {
          'code': value.value,
          'name': value.label
        }
        this.courseOptions = []
        this.handleReset('applyForm')
        this.applyForm = Object.assign(this.applyForm, {
          exp_type: 'COURSE',
          institute: institute,
          teacher_code: teacher.code || '',
          teacher_name: teacher.name || '',
          course_code: ''
        })
        if (teacher.code) {
          this.courseLoading = true
          getCourseByTeacherCode(teacher.code).then(response => {
            let res = response.data
            if (res.code && res.data.length > 0) {
              this.courseOptions = res.data.map(item => {
                return {
                  code: item.code,
                  name: item.name
                }
              })
            } else {
              this.$Notice.error({
                title: res.code ? '提示' : '抱歉，获取课程列表失败',
                desc: res.code ? '该教师暂无课程，请选择其他教师。' : res.info
              })
              this.courseOptions = []
            }
            this.courseLoading = false
          }).catch(error => {
            this.courseOptions = []
            console.log(error.stack)
            this.courseLoading = false
            this.$Notice.error({
              title: '抱歉，发生内部错误，请刷新后重试',
              desc: err.stack
            })
          })
        }
      }
    },
    handleCheckAllClasses () {
      if (this.classesIndeterminate) {
        this.classesCheckAll = false
      } else {
        this.classesCheckAll = !this.classesCheckAll
      }
      this.classesIndeterminate = false
      if (this.classesCheckAll) {
        this.applyForm.classes = this.classesList.map(item => {
          return JSON.stringify(item)
        })
      } else {
        this.applyForm.classes = []
      }
    },
    // 选择课程后的回调，根据 课程代码 和 教师代码 获取该课程拥有的班级
    async onSelectCourse (value) {
      this.classesList = []
      this.applyForm.classes = this.isModified ? this.applyForm.classes : []
      if (value) {
        this.classesLoading = true
        let response = await getClassesByCourse(value, this.applyForm.teacher_code)
        let res = response.data
        if (res.code && res.data.length > 0) {
          // 删掉不需要的键值对
          this.classesList = JSON.parse(JSON.stringify(res.data, ['grade', 'major', 'institute', 'sclass']))
        } else {
          this.$Notice.error({
            title: res.code ? '提示' : '抱歉，获取班级列表失败',
            desc: res.code ? '该课程暂无班级，请选择其他课程。' : res.info
          })
          this.classesList = []
        }
        this.classesLoading = false
      }
    },
    // 当“耗材、系统、软件需求”失去焦点时，把当前值填充到其余实验项目空的需求值上
    blur_need (type, baseIndex) {
      let baseItems = this.applyForm.expBaseInfoItems
      const need = {
        'resources': baseItems[baseIndex].resources,
        'system': baseItems[baseIndex].system,
        'software': baseItems[baseIndex].software
      }
      let val = need[type]
      if (val) {
        baseItems.forEach((item, index) => {
          if (item[type] === null || item[type] === '') {
            item[type] = val
          }
        })
      }
    },
    // 新增实验时间
    add_time (item) {
      item.push({
        guid: generateGuid(),
        institute: this.applyForm.expBaseInfoItems[0].expTimeItems[0].institute,
        sweek: null,
        sdate: null,
        section: [],
        classroom: [],
        laboratoryList: [],
        labLoading: false
      })
    },
    // 删除实验时间
    remove_time (expBaseInfoItem, item, index) {
      if (expBaseInfoItem.expTimeItems.indexOf(item) !== -1) {
        expBaseInfoItem.expTimeItems.splice(index, 1)
      }
    },
    // 改变实验时间的回调函数，用于查找选择的时间段内可用的实验室
    onChangeTime (baseIndex, timeIndex, type) {
      if (type === 'section') {
        let learntimeItems = this.$refs.learntime
        learntimeItems[baseIndex].blur()
      }
      // if (this.timer) clearTimeout(this.timer)
      // this.timer = setTimeout(() => {
      if (!this.isFilledForming || (this.isFilledForming && this.isFilledFormByData)) {
        let timeItems = this.applyForm.expBaseInfoItems[baseIndex].expTimeItems
        let timeItem = timeItems[timeIndex]
        let requestTime = {
          'sweek': timeItem.sweek,
          'sdate': parseInt(timeItem.sdate),
          'section': timeItem.section
        }
        let requestInstitute = timeItem.institute
        timeItem.classroom = []
        if (timeItem.institute && requestTime.sweek && requestTime.sdate && requestTime.section.length > 0) {
          timeItem.labLoading = true
          getLabByTimes(requestTime, requestInstitute, this.isModified ? this.applyForm.app_code : '').then(response => {
            let res = response.data
            if (res.code && res.data.length > 0) {
              // let intersection = res.data[0]
              // 循环通过是否有同样的code交集
              // for (let i = 1; i < res.data.length; i++) {
              //   intersection = [...intersection].filter(x => [...res.data[i]].some(y => y.code === x.code))
              // }
              timeItem.laboratoryList = res.data
              timeItem.labLoading = false
            } else {
              this.$Notice.error({
                title: res.code ? '提示' : '抱歉，获取实验室列表失败',
                desc: res.code ? '暂无实验室可申请。' : res.info
              })
              timeItem.labLoading = false
            }
            // eslint-disable-next-line
          }).catch(error => {
            console.log(error)
            this.$Notice.error({
              title: '提示',
              desc: '暂无实验室可申请'
            })
            timeItem.labLoading = false
          })
        }
      }
      // }, 200)
    },
    // 新增实验项目
    add_exp_info () {
      let item = this.applyForm.expBaseInfoItems[0]
      this.applyForm.expBaseInfoItems.push({
        guid: generateGuid(),
        sid: this.applyForm.expBaseInfoItems.length + 1,
        type: item.type,
        title: null,
        learntime: item.learntime,
        resources: item.resources,
        system: item.system,
        software: item.software,
        expTimeItems: [
          {
            guid: generateGuid(),
            institute: this.applyForm.expBaseInfoItems[0].expTimeItems[0].institute,
            sweek: null,
            sdate: null,
            section: [],
            classroom: null,
            laboratoryList: [],
            labLoading: false
          }
        ]
      })
      this.$nextTick(() => {
        // 跳转到对应的锚点
        location.hash = '#exp_item_' + this.applyForm.expBaseInfoItems.length
        // Velocity(this.$refs.baseInfoRef[this.applyForm.expBaseInfoItems.length - 1], 'scroll', {
        //   // offset: -260,
        //   // container: this.$parent.$el,
        //   container: document.querySelector('.content-wrapper.ivu-layout-content'),
        //   duration: 800
        // })
      })
    },
    // 删除实验项目
    remove_exp_info (item, index) {
      let items = this.applyForm.expBaseInfoItems
      if (items.indexOf(item) !== -1) {
        items.splice(index, 1)
      }
      this.$nextTick(() => {
        document.querySelector(`a[data-href='#exp_item_${index === 0 ? 1 : index}']`).click()
      //   Velocity(this.$refs.baseInfoRef[index === items.length ? this.applyForm.expBaseInfoItems.length - 1 : index], 'scroll', {
      //     // container: this.$parent.$el,
      //     container: document.querySelector('.content-wrapper.ivu-layout-content'),
      //     duration: 600
      //   })
      })
    },
    // 提交表单
    handleSubmit (name) {
      this.submitLoading = true
      this.$refs[name].validate(async (valid) => {
        if (valid) {
          this.showSpinWithTip('提交申请表中，请稍等...')
          let formData = JSON.parse(JSON.stringify(this.applyForm, function (key, value) {
            if (key === 'guid' || key === 'laboratoryList' || key === 'labLoading') {
              return undefined
            } else {
              return value
            }
          }))
          for (let i = 0; i < formData.classes.length; i++) {
            formData.classes[i] = JSON.parse(formData.classes[i])
          }
          try {
            let response = this.isModified ? await editApply(JSON.stringify(formData)) : await submitApply(JSON.stringify(formData))
            this.$Spin.hide()
            let res = response.data
            if (res.code) {
              this.handleReset('applyForm')
              if (this.isModified) {
                this.$emit('saveSuccess', true)
              } else {
                this.$Notice.success({
                  title: '成功',
                  desc: '成功提交实验室申请表。'
                })
              }
            } else {
              if (this.getElClass(res.data) === 'Array' && res.data.length > 0) {
                this.occupyData.table = []
                for (let i = 0; i < res.data.length; i++) {
                  for (let j = 0; j < res.data[i].length; j++) {
                    let item = {}
                    item.expIndex = i + 1
                    item.weekNumber = res.data[i][j].usageTime.sweek
                    item.week = res.data[i][j].usageTime.sdate
                    item.section = res.data[i][j].usageTime.section
                    item.code = res.data[i][j].labCode
                    item.teacherName = res.data[i][j].teacherName
                    item.courseName = res.data[i][j].courseName
                    item.experimentNumber = res.data[i][j].experimentNumber
                    item.experimentName = res.data[i][j].experimentName
                    item.appCode = res.data[i][j].app_code
                    let children = this.occupyColumns[this.occupyColumns.length - 1].children
                    if (item.appCode === '0' && children && children[children.length - 1].key === 'action') {
                      children.pop()
                    } else if (item.appCode !== '0' && children && children[children.length - 1].key !== 'action') {
                      children.push({
                        title: '操作',
                        align: 'center',
                        key: 'action',
                        width: 80,
                        render: (h, params) => {
                          return h('div', [
                            h('Button', {
                              props: {
                                type: 'primary',
                                size: 'small'
                              },
                              on: {
                                click: () => {
                                  this.openDetail(params)
                                }
                              }
                            }, '查看详情')
                          ])
                        }
                      })
                    }
                    this.occupyData.table.push(item)
                  }
                }
                this.modal.occupy = {
                  'show': true,
                  'title': res.info ? res.info : '抱歉，实验室使用时间冲突，请重新选择'
                }
              } else {
                this.$Notice.error({
                  title: '抱歉，提交失败',
                  desc: res.info
                })
              }
            }
          } catch (error) {
            this.$Spin.hide()
            console.log(error.stack)
            this.$Notice.error({
              title: '提交失败',
              desc: error.stack
            })
          }
        } else {
          this.submitLoading = false
          this.$Notice.error({
            title: '提交失败',
            desc: '抱歉，无法提交，请先完善表单信息再提交。'
          })
        }
      })
      this.submitLoading = false
    },
    // 重置表单
    async handleReset (name, reGetCourse) {
      if (reGetCourse) {
        if (this.applyForm.teacher_code !== this.$store.state.user.userCode) {
          this.courseLoading = true
          this.courseOptions = []
          getCourseByTeacherCode(this.$store.state.user.userCode).then(response => {
            let res = response.data
            if (res.code && res.data.length > 0) {
              this.courseOptions = res.data.map(item => {
                return {
                  code: item.code,
                  name: item.name
                }
              })
            } else {
              this.$Notice.error({
                title: res.code ? '提示' : '抱歉，获取课程列表失败',
                desc: res.code ? '该教师暂无课程，请选择其他教师。' : res.info
              })
              this.courseOptions = []
            }
            this.courseLoading = false
          }).catch(error => {
            this.courseOptions = []
            console.log(error.stack)
            this.courseLoading = false
            this.$Notice.error({
              title: '抱歉，发生内部错误，请刷新后重试',
              desc: err.stack
            })
          })
        }
      }
      let firstBaseGuid = this.applyForm.expBaseInfoItems[0].guid || generateGuid()
      this.$refs[name].resetFields()
      // this.applyForm.teacher_code = this.$store.state.user.userCode
      this.applyForm = {
        exp_type: 'COURSE',
        app_code: this.isModified ? this.applyForm.app_code : undefined,
        institute: this.$store.state.user.department || '',
        teacher_code: this.$store.state.user.userCode || '',
        teacher_name: this.$store.state.user.userName || '',
        course_code: '',
        textbook: null,
        classes: [],
        // stu_num: null,
        expBaseInfoItems: [
          {
            guid: firstBaseGuid,
            sid: 1,
            type: null,
            title: null,
            learntime: null,
            resources: null,
            system: null,
            software: null,
            expTimeItems: [
              {
                guid: generateGuid(),
                institute: this.$store.state.user.department || '',
                sweek: null,
                sdate: null,
                section: [],
                classroom: [],
                laboratoryList: [],
                labLoading: false
              }
            ]
          }
        ]
      }
      await this.$nextTick(() => {
        location.hash = 'course_info'
        localStorage.removeItem('applyForm')
        localStorage.removeItem('courseOptions')
        localStorage.removeItem('classesList')
      })
    },
    // 通过从后台获取的数据填充到当前表单中
    async fillFormByData (data) {
      this.isFilledForming = true
      this.showSpinWithTip('加载历史数据中...')
      this.historyLoading = true
      if (this.isModified) {
        // 直接拿申请人的学院
        try {
          let res = await getUserByCode(data.teacher_code)
          res = res.data
          if (res.code) {
            data.institute = res.data.department
            // 如果有获取是管理员且非修改状态的话，需要重新获取教师列表
            if (this.userAccess.some(item => { return ['ROLE_ROOT', 'ROLE_SCHOOL_ADMIN', 'ROLE_INSTITUTE_ADMIN'].indexOf(item) > -1 }) && !this.isModified) {
              try {
                let temp = await this.getTeacherOptions(data.institute)
                temp = temp.data
                if (temp.code) {
                  this.teacherOptions = temp.data
                } else {
                  this.$Notice.error({
                    title: '获取教师列表失败，请刷新后重试',
                    desc: temp.info
                  })
                  this.$Spin.hide()
                  this.historyLoading = false
                  return false
                }
              } catch (error) {
                console.log(error)
                this.$Notice.error({
                  title: '获取教师列表失败，请刷新后重试',
                  desc: error
                })
                this.$Spin.hide()
                this.historyLoading = false
                return false
              }
            }
          } else {
            this.$Notice.error({
              title: '操作失败',
              desc: '抱歉，获取原表单中教师信息失败，请刷新后重试。' + res.info
            })
            this.$Spin.hide()
            this.historyLoading = false
            return false
          }
        } catch (error) {
          console.log(error)
          this.$Notice.error({
            title: '操作失败',
            desc: '抱歉，获取原表单中教师信息失败，请刷新后重试。' + error
          })
          this.$Spin.hide()
          this.historyLoading = false
          return false
        }
        this.applyForm.institute = data.institute
        this.courseName = data.course_name
        this.applyForm.teacher_code = data.teacher_code
        this.applyForm.teacher_name = data.teacher_name
        this.onSelectCourse(data.course_code)
        for (let i = 0; i < data.classes.length; i++) {
          data.classes[i] = JSON.stringify(data.classes[i])
        }
      }
      if (data.exp_type === 'COURSE') {
        for (let i = 0; i < data.expBaseInfoItems.length; i++) {
          const item = data.expBaseInfoItems[i]
          item.guid = generateGuid()
          item.sid = this.isModified ? item.sid : ''
          item.learntime = item.plan_hours
          let tempMap = new Map()
          item.expTimeItems = []
          delete item.plan_hours
          delete item.actual_hours
          delete item.expTimeItemsTrain
          // 遍历各个子实验时间，根据index合并为原始数值
          item.expTimeItemsCourse.forEach(c => {
            if (!tempMap.has(c.index)) {
              tempMap.set(c.index, {
                institute: c.classroom.institute,
                sweek: c.expItemTime.sweek,
                sdate: c.expItemTime.sdate + '',
                section: new Set().add(c.expItemTime.section),
                classroom: new Set().add(this.isModified ? c.classroom.code : null)
              })
            } else {
              tempMap.get(c.index).section.add(c.expItemTime.section)
              tempMap.get(c.index).classroom.add(this.isModified ? c.classroom.code : null)
            }
          })
          // 把 子实验时间 expTimeItemsCourse 转换为数组
          item.expTimeItemsCourse = Array.from(tempMap)
          // 遍历一次转换的数组，获取各个实验的可用实验室
          for (let j = 0; j < item.expTimeItemsCourse.length; j++) {
            const c = item.expTimeItemsCourse[j]
            c[1].section = Array.from(c[1].section)
            c[1].guid = generateGuid()
            let time = {
              'sweek': c[1].sweek,
              'sdate': parseInt(c[1].sdate),
              'section': c[1].section
            }
            let requestInstitute = c[1].institute
            try {
              let res = await getLabByTimes(time, requestInstitute, this.isModified ? data.app_code : '')
              res = res.data
              if (res.code) {
                if (res.data.length > 0) {
                  c[1].laboratoryList = res.data.map(item => {
                    return {
                      code: item.code,
                      name: item.name,
                      capacity: item.capacity,
                      status: item.status
                    }
                  })
                } else {
                  c[1].laboratoryList = []
                  this.$Notice.error({
                    title: '暂无实验室列表',
                    desc: '抱歉，该时间下暂无空余实验室，请选择其他实验时间'
                  })
                }
              } else {
                this.$Notice.error({
                  title: '获取实验室列表失败',
                  desc: res.info
                })
                c[1].laboratoryList = []
              }
              c[1].classroom = this.isModified ? Array.from(c[1].classroom) : []
              item.expTimeItems.push(c[1])
            } catch (error) {
              this.$Spin.hide()
              this.historyLoading = false
              console.log(error)
              c[1].laboratoryList = []
              c[1].classroom = this.isModified ? Array.from(c[1].classroom) : []
              item.expTimeItems.push(c[1])
            }
            c[1].labLoading = false
          }
          delete item.expTimeItemsCourse
        }
        this.$nextTick(() => {
          if (this.isModified) {
            this.applyForm = data
          } else {
            // 此时为导入历史申请表
            this.applyForm.textbook = data.textbook
            this.applyForm.expBaseInfoItems = data.expBaseInfoItems
          }
        })
        if (!this.teaLoading) {
          this.$nextTick(() => {
            this.historyLoading = false
            setTimeout(() => {
              this.isFilledFormByData = true
            }, 1000)
            this.$emit('hide-spin')
          })
        }
      }
      this.$Spin.hide()
    },
    openDetail (params) {
      this.modal.detail = {
        show: true,
        title: params.row.teacherName + '老师的' + '《' + params.row.courseName + '》课程相关的实验课信息登记表',
        code: params.row.appCode || ''
      }
    },
    // 显示带文字提示的Spin
    showSpinWithTip (tip) {
      this.$Spin.show({
        render: (h) => {
          return h('div', {'class': 'ivu-spin-large'}, [
            h('span', {
              'class': 'ivu-spin-dot',
              style: {
                display: 'inline-block'
              }
            }),
            h('div', tip)
          ])
        }
      })
    },
    leave (el, done) {
      Velocity(el, {
        scale: 1,
        backgroundColorRed: 250,
        backgroundColorGreen: 220,
        backgroundColorBlue: 174,
        backgroundColorAlpha: 0.87
      }, {
        duration: 300,
        easing: 'linear'
      })
      Velocity(el, {
        scale: 0.6
      }, {
        duration: 0,
        easing: 'ease'
      })
      Velocity(el, {
        scale: 0,
        height: 0,
        opacity: 0
      }, {
        duration: 500,
        easing: 'ease',
        complete: done
      })
    },
    /**
     * 利用MutationObserver实现监听元素class的变化
     */
    startMutationObserver () {
      let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
      let element = document.querySelector('.form-wrapper')
      this.observer = new MutationObserver(mutations => {
        for (let mutation of mutations) {
          if (mutation.type === 'attributes' && mutation.attributeName === 'class' && mutation.target.className.split(' ').indexOf('ivu-form-item') > -1) {
            // 高亮显示有错误的课程基本信息
            if (document.querySelector('#course_info').querySelectorAll('.ivu-form-item-error').length > 0) {
              document.querySelector("a[href='#course_info']") && document.querySelector("a[href='#course_info']").classList.add('text-danger')
            } else {
              document.querySelector("a[href='#course_info']") && document.querySelector("a[href='#course_info']").classList.remove('text-danger')
            }
            // 高亮显示有错误的实验项目
            document.querySelectorAll('.list-complete-item').forEach(expItem => {
              if (expItem.querySelectorAll('.ivu-form-item-error').length > 0) {
                if (document.querySelector('.ivu-anchor').querySelector("a[href='#" + expItem.id + "']")) {
                  document.querySelector('.ivu-anchor').querySelector("a[href='#" + expItem.id + "']").classList.add('text-danger')
                }
              } else {
                let el = document.querySelector('.ivu-anchor').querySelector("a[href='#" + expItem.id + "']")
                if (el) {
                  el.classList.remove('text-danger')
                }
              }
            })
          }
        }
      })
      this.observer.observe(element, {
        attributes: true,
        attributeFilter: ['class'],
        attributeOldValue: true,
        subtree: true,
        childList: true
      })
    },
    getElClass (o) {
      if (o === null) return 'Null'
      if (o === undefined) return 'undefined'
      return Object.prototype.toString.call(o).slice(8, -1)
    }
  },
  watch: {
    // 监听applyForm数据的变化，如果发生改变则保存到localStorage
    applyForm: {
      handler: function (val, oldVal) {
        if (!this.isModified) {
          this.$emit('update:canImportHistory', this.applyForm.institute && this.applyForm.teacher_code && this.applyForm.teacher_name && this.applyForm.course_code && this.applyForm.classes.length > 0)
          localStorage.setItem('applyForm', JSON.stringify(val))
        }
      },
      deep: true
    },
    courseOptions: function (val, oldVal) {
      if (!this.isModified) {
        localStorage.setItem('courseOptions', JSON.stringify(val))
      }
    },
    classesList: function (val, oldVal) {
      if (!this.isModified) {
        localStorage.setItem('classesList', JSON.stringify(val))
      }
    },
    submitLoading: function (val, oldVal) {
      this.$emit('update:submitLoading', val)
    },
    'applyForm.teacher_code': function (val, oldVal) {
      this.$emit('update:teacher_code', val)
    },
    'applyForm.course_code': function (val, oldVal) {
      this.$emit('update:course_code', val)
    },
    'applyForm.classes': function (val, oldVal) {
      if (val.length === this.classesList.length && val.length > 0) {
        this.classesIndeterminate = false
        this.classesCheckAll = true
      } else if (val.length > 0) {
        this.classesIndeterminate = true
        this.classesCheckAll = false
      } else {
        this.classesIndeterminate = false
        this.classesCheckAll = false
      }
    },
    pdfData: {
      async handler (val, oldVal) {
        this.historyLoading = true
        let access = this.$store.state.user.access
        let isInstituteAdmin = access.indexOf('ROLE_SCHOOL_ADMIN') > -1 || access.indexOf('ROLE_INSTITUTE_ADMIN') > -1 || access.indexOf('ROLE_ROOT') > -1
        let isSchoolAdmin = access.indexOf('ROLE_SCHOOL_ADMIN') > -1 || access.indexOf('ROLE_ROOT') > -1
        if (this.instituteOptions.indexOf(val.institute) < 0) {
          this.$emit('hide-spin')
          this.$Notice.error({
            title: '上传失败',
            desc: `抱歉，该教学大纲的 ${val.institute} 不存在，请重新上传其他教学大纲。`
          })
          this.historyLoading = false
          return false
        }
        if (val.institute === this.$store.state.user.department || isSchoolAdmin) {
          this.institute = val.institute
          // 判断教师是否一致，或为管理员
          if (val.teacher_name === this.$store.state.user.userName || isInstituteAdmin || isSchoolAdmin) {
            await this.handleReset('applyForm')
            // 判断是否需要获取教师列表
            if (isInstituteAdmin) {
              // 如果是管理员，则从教师列表中获取和pdf中读取的教师
              let teacher = this.teacherOptions.filter(item => {
                return item.name === val.teacher_name
              })
              // 数组长度为0则表示无匹配的教师
              if (teacher.length === 0) {
                this.$Notice.error({
                  title: '提示',
                  desc: '抱歉，教师列表中无该教学大纲的授课教师，请选择其他教师'
                })
                this.historyLoading = false
                return false
              } else {
                this.applyForm.teacher_code = teacher[0].code
                this.applyForm.teacher_name = teacher[0].name
              }
            } else {
              // 非管理员的用户只能上传自己的教学大纲
              this.applyForm.teacher_code = this.$store.state.user.userCode
              this.applyForm.teacher_name = this.$store.state.user.userName
            }
            if (this.applyForm.teacher_code) {
              try {
                let res = await getCourseByTeacherCode(this.applyForm.teacher_code)
                res = res.data
                if (res.code && res.data.length > 0) {
                  this.courseOptions = res.data
                  for (let i = 0; i < this.courseOptions.length; i++) {
                    if (this.courseOptions[i].name === val.course_code) {
                      this.applyForm.course_code = this.courseOptions[i].code
                      break
                    }
                  }
                  if (this.applyForm.course_code) {
                    await this.onSelectCourse(this.applyForm.course_code)
                    this.applyForm.textbook = val.textbook
                    val.expBaseInfoItems.forEach(item => {
                      item.expTimeItems.forEach(time => {
                        time.institute = this.applyForm.institute
                      })
                    })
                    // 赋值第一个元素
                    this.applyForm.expBaseInfoItems[0].sid = val.expBaseInfoItems[0].sid
                    this.applyForm.expBaseInfoItems[0].type = val.expBaseInfoItems[0].type
                    this.applyForm.expBaseInfoItems[0].title = val.expBaseInfoItems[0].title
                    this.applyForm.expBaseInfoItems[0].learntime = val.expBaseInfoItems[0].learntime
                    this.applyForm.expBaseInfoItems[0].classroom = val.expBaseInfoItems[0].classroom
                    this.applyForm.expBaseInfoItems[0].expTimeItems = val.expBaseInfoItems[0].expTimeItems
                    val.expBaseInfoItems.splice(0, 1)
                    this.applyForm.expBaseInfoItems.push(...JSON.parse(JSON.stringify(val.expBaseInfoItems)))
                    setTimeout(() => {
                      this.historyLoading = false
                      this.$emit('hide-spin')
                    }, 1000)
                  } else {
                    this.historyLoading = false
                    this.$emit('hide-spin')
                    this.$Notice.error({
                      title: '提示',
                      desc: '抱歉，该教师无相关教程。'
                    })
                  }
                } else {
                  this.$emit('hide-spin')
                  this.historyLoading = false
                  this.$Notice.error({
                    title: res.code ? '提示' : '抱歉，获取课程列表失败',
                    desc: res.code ? '该教师暂无课程，请选择其他教师。' : res.info
                  })
                  this.courseOptions = null
                }
              } catch (error) {
                console.log(error)
                this.historyLoading = false
                this.$emit('hide-spin')
                this.$Notice.error({
                  title: '上传失败',
                  desc: '抱歉，发生了未知错误，请稍后重试。'
                })
              }
            } else {
              this.$emit('hide-spin')
              this.historyLoading = false
              this.$Notice.error({
                title: '上传失败',
                desc: '抱歉，该教学大纲的教师不在教师列表中。'
              })
            }
          } else {
            this.$emit('hide-spin')
            this.historyLoading = false
            this.$Notice.error({
              title: '上传失败',
              desc: '抱歉，只能上传任课教师为本人的教学大纲'
            })
          }
        } else {
          this.$emit('hide-spin')
          this.historyLoading = false
          this.$Notice.error({
            title: '上传失败',
            desc: isInstituteAdmin ? '抱歉，只能上传开课院系为本学院的教学大纲' : '抱歉，只能上传本人的教学大纲'
          })
        }
      }
      // ,deep: true
    }
  }
}
</script>
